package com.xuecheng.content.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.qo.QueryCourseModel;
import com.xuecheng.api.content.model.vo.CourseBaseVo;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.CourseMarketService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.Date;
import java.util.List;


/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {


    @Autowired
    private CourseMarketService courseMarketService;

    @Override
    public List<CourseBase> queryAll() {
        List<CourseBase> lists = list();
        return lists;
    }

    /**
     * 步骤分析
     * 1.是否开启事务  不
     * 2.判断关键数据
     * 分页数据
     * 查询条件 名称模糊查询 like
     * 3.构建mp分页对象
     * 4.构建查询条件LambdaQueryWrapper
     * 5.查询数据
     * 6.获取数据封装并返回
     * 封装PageVo数据
     */
    @Override
    public PageVO queryCourseList(PageRequestParams params, QueryCourseModel model, Long companyId) {

        LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();

        Page<CourseBase> page = new Page<>(params.getPageNo(), params.getPageSize());

        /**
         * 添加教学机构身份认证
         */
        wrapper.eq(CourseBase::getCompanyId, companyId);

        //1.判断分页数据
        if (params.getPageNo() < 1) {
            //如小于1，则给它默认值
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (params.getPageSize() < 1) {
            //如小于1，则给它默认值
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }


        //3.名称模糊查询 like
        if (!StringUtil.isEmpty(model.getCourseName())) {
            wrapper.eq(CourseBase::getAuditStatus, model.getAuditStatus())
                    .like(CourseBase::getName, model.getCourseName());
        }
        //3.分页数据
        Page<CourseBase> courseBasePage = this.page(page, wrapper);
        //3.1获取每页数据
        List<CourseBase> records = courseBasePage.getRecords();

        //TODO: 数据转换MapStruct
        List<CourseBaseDTO> dtos = Collections.emptyList();
        dtos = CourseBaseConvert.INSTANCE.entitys2dtos(records);
        //4.0查询的数据封装到PageVO
        //每页数据//总页数//当前页//每页大小
        return new PageVO(dtos, page.getTotal(), page.getCurrent(), page.getSize());
    }

    /**
     * 业务分析：
     * 1.是否要开启事务
     * 如果是增删改操作，必须要开启事务
     * 2.判断关键数据
     * 有此数据才可以进行操作，一般有前端来传入
     * 来源：
     * 数据库表约束
     * 前端页面的表单说明
     * 为必填项：红星
     * api接口文档（Yapi）
     * 3.判断业务数据（添加没有业务数据判断）
     * 系统中存在的数据，如果数据状态有问题，当前操作要终止，一般数据来源于后端
     * 4.判断数据是否要被赋值（默认值）
     * status：数据库已经赋值，无需操作
     * 审核状态 auditStatus：新添加的课程默认审核状态--未提交（状态码）
     * 5.将dto转为po数据
     * 因为mp的api只能对po数据进行操作
     * 6.保存数据并返回结果，判断结果是否成功
     * 7.如果操作成功，将数据转为dto并返回
     */
    @Override
    @Transactional
    public CourseBaseDTO createCourse(CourseBaseDTO dto) {

        //2.判断关键数据
        extracted(dto);
        //3.设置商家id
        //4.给业务数据数据赋值状态--未提交
        //5.业务数据到数据库--需要转换
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2po(dto);
        courseBase.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());


        //6.保存数据并返回结果，判断结果是否成功
        boolean courseBaseSave = this.save(courseBase);
        //6.1如果操作成功，将数据转为dto并返回
        if (!courseBaseSave) {
            throw new RuntimeException("添加基础课程信息失败");
        }
        //6.2判断是否有营销课程
        CourseMarket market = new CourseMarket();
        market.setCourseId(courseBase.getId());
        market.setCharge(dto.getCharge());
        //基本课程免费，营销课程收费，需要判断是收费还是免费
        String charge = dto.getCharge();
        //收费的  CourseChargeEnum 收费 免费 枚举类
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)) {
            //判断收费价格是否为空
            if (ObjectUtils.isEmpty(dto.getPrice())) {
                throw new RuntimeException("营销价格不能为空");
            }
            //添加营销课程费用信息
            market.setPrice(dto.getPrice().floatValue());
        }
        //6.3添加营销信息
        boolean save = courseMarketService.save(market);
        if (!save) {
            throw new RuntimeException("添加营销课程信息失败");
        }


        //7.获取最新数据并封装dto返回给前端
        CourseBase base = this.getById(courseBase.getId());
        return CourseBaseConvert.INSTANCE.entity2dto(base);
    }

    /**
     * 业务分析：
     * 1.关键数据
     * courseBaseId  companyId
     * 2.判断业务数据
     * 课程基本信息
     * 判断是否存在
     * 是否是同家机构
     * 是否删除
     * 营销课程
     * 3.查询结果封装dto返回
     */
    @Override
    public CourseBaseDTO getCourseBaseById(Long courseBaseId, Long companyId) {

        /**
         * 添加教学机构身份认证
         */
        if (ObjectUtils.isEmpty(companyId)) {
            throw new RuntimeException("教学机构ID不能为空");
        }
        if (ObjectUtils.isEmpty(courseBaseId)) {
            throw new RuntimeException("课程ID不能为空");
        }
        //通过公司id和课程id查询信息
        CourseBase courseBase = getCourseBaseByCompanyIdAndCourseId(courseBaseId, companyId);
        //查看有没有营销信息
        CourseMarket courseMarket = getCourseMarketById(courseBaseId);
        //封装po-->dto返回
        CourseBaseDTO courseBaseDTO = CourseBaseConvert.INSTANCE.entity2dto(courseBase);
        //营销数据
        courseBaseDTO.setCharge(courseMarket.getCharge());
        courseBaseDTO.setPrice(BigDecimal.valueOf(courseMarket.getPrice()));


        return courseBaseDTO;
    }

    //判断营销课程存在不
    private CourseMarket getCourseMarketById(Long courseBaseId) {
        LambdaQueryWrapper<CourseMarket> wrapperMarket = new LambdaQueryWrapper<>();
        wrapperMarket.eq(CourseMarket::getCourseId, courseBaseId);
        CourseMarket courseMarket = courseMarketService.getOne(wrapperMarket);
        if (ObjectUtils.isEmpty(courseMarket)) {
            throw new RuntimeException("营销课程不存在");
        }
        return courseMarket;
    }

    //通过公司id和课程id查询信息
    private CourseBase getCourseBaseByCompanyIdAndCourseId(Long courseBaseId, Long companyId) {
        //查询条件
        LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CourseBase::getId, courseBaseId)
                .eq(CourseBase::getCompanyId, companyId);
        //获取信息
        CourseBase courseBase = this.getOne(wrapper);
        //判断课程存在不
        if (ObjectUtils.isEmpty(courseBase)) {
            throw new RuntimeException("课程信息不存在");
        }
        if (!(CommonEnum.USING_FLAG.getCodeInt().equals(courseBase.getStatus()))) {
            throw new RuntimeException("课程信息被逻辑删除");
        }
        return courseBase;
    }

    /**
     * 业务分析：
     * 1.判断关键数据
     * 可以使用添加的判断
     * 修改时：课程id是必须存在
     * 2.判断业务数据
     * 课程基础信息
     * 判断是否存在
     * 判断是否是同一家教学机构
     * 判断是否删除
     * 判断课程审核状态：未提交、审核未通过
     * 课程营销
     * 3.修改数据内容
     * 课程基础信息表
     * 有些内容是不容修改的：courseBaseId、companyid、auditstatus、status
     * 课程营销数据表
     * charge price
     * 修改数据时要判断修改后结果
     * <p>
     * 4.返回前端最新的数据库的数据并封装为dto返回
     */
    @Override
    @Transactional
    public CourseBaseDTO modifyCourseBase(CourseBaseDTO dto) {
        //判断关键数据存在不
        extracted(dto);
        //判断修改的课程id
        if (ObjectUtils.isEmpty(dto.getCourseBaseId())) {
            throw new RuntimeException("修改的课程ID不能为空");
        }
        //通过公司id和课程id查询信息
        //2.判断业务数据
        //    课程基础信息
        //        判断是否存在
        //        判断是否是同一家教学机构
        //        判断是否删除
        CourseBase courseBase = getCourseBaseByCompanyIdAndCourseId(dto.getCourseBaseId(), dto.getCompanyId());
        //判断课程审核状态：未提交、审核未通过
        //课程基本信息的状态不能为'已提交' 、'审核通过'、'课程已发布' 状态。
        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)) {
            throw new RuntimeException("课程基本信息的状态不能为'已提交' 、'审核通过'、'课程已发布' 状态");

        }
        //判断营销课程存在不
        getCourseMarketById(dto.getCourseBaseId());

        //3.修改数据内容
        //3.1传入数据库数据po
        CourseBase base = CourseBaseConvert.INSTANCE.dto2po(dto);

        //课程基础信息表
        //有些内容是不容修改的：courseBaseId、companyid、auditstatus、status
        base.setCoursePubId(null);
        //设置状态未提交
        base.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());
        base.setStatus(null);
        boolean save = this.saveOrUpdate(base);
        if (!save) {
            throw new RuntimeException("修改基本数据失败");
        }
        //课程营销数据表
        //charge price
        LambdaUpdateWrapper<CourseMarket> wrapper = new LambdaUpdateWrapper<>();
        //判断课程id
        wrapper.eq(CourseMarket::getCourseId, dto.getCourseBaseId())
                //设置课程是否收费状态
                .set(CourseMarket::getCharge, dto.getCharge());
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(dto.getCharge())) {
            if (ObjectUtils.isEmpty(dto.getPrice())) {
                throw new RuntimeException("收费价格不能为空");
            }
            wrapper.set(CourseMarket::getPrice, dto.getPrice());
        }

        boolean courseMarketUpdate = courseMarketService.update(wrapper);
        //修改数据时要判断修改后结果
        if (!courseMarketUpdate) {
            throw new RuntimeException("营销课程修改失败");
        }

        //4.返回前端最新的数据库的数据并封装为dto返回
        //通过dto  id 查询基础信息和营销信息
        return getDataBaseMarketById(dto);
    }

    /**
     * 需求的分析：
     * 1.删除需要事务
     * 2.关键数据判断
     * courseBaseId 课程id 必须
     * companyId      机构id 必须
     * 3.只需要对course_base 操作
     * 3.1判断数据在不在
     * 3.2程基本信息的状态不能为'已提交' 、'审核通过'、'课程已发布' 状态。
     */
    @Override
    @Transactional
    public void removeCourseBase(Long courseBaseId, Long companyId) {
        if (ObjectUtils.isEmpty(courseBaseId)) {
            throw new RuntimeException("删除的课程ID不能为空");
        }
        LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CourseBase::getCompanyId, companyId)
                .eq(CourseBase::getId, courseBaseId);
        CourseBase courseBase = this.getOne(wrapper);
        if (ObjectUtils.isEmpty(courseBase)) {
            throw new RuntimeException("没有此课程信息");
            //ExceptionCast.cast(ContentErrorCode.E_120015);
        }
        //课程基本信息的状态不能为'已提交' 、'审核通过'、'课程已发布' 状态。
        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)) {
            throw new RuntimeException("课程基本信息的状态不能为'已提交' 、'审核通过'、'课程已发布' 状态");

        }

        //逻辑删除
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CourseBase::getId, courseBaseId)
                .eq(CourseBase::getCompanyId, companyId)
                .set(CourseBase::getChangeDate, new Date())
                .set(CourseBase::getStatus, CommonEnum.DELETE_FLAG.getCodeInt());
        this.update(updateWrapper);
    }

    //查询Base和Market数据并封装到DTO
    private CourseBaseDTO getDataBaseMarketById(CourseBaseDTO dto) {
        //获取基本课程数据
        CourseBase courseBase = this.getById(dto.getCourseBaseId());
        //封装到dto
        CourseBaseDTO courseBaseDTO = CourseBaseConvert.INSTANCE.entity2dto(courseBase);

        courseBaseDTO.setCharge(dto.getCharge());
        courseBaseDTO.setPrice(dto.getPrice());


        return courseBaseDTO;
    }


    /**
     * 此方法用于判断必须传入数据存在不
     *
     * @param dto CourseBaseDTO
     */
    private void extracted(CourseBaseDTO dto) {
        if (ObjectUtils.isEmpty(dto.getCompanyId())) {
            throw new RuntimeException("公司id不能为空");
        }
        if (StringUtils.isBlank(dto.getGrade())) {
            throw new RuntimeException("课程等级不能为空");
        }
        if (StringUtils.isBlank(dto.getMt())) {
            throw new RuntimeException("大分类不能为空");
        }
        if (StringUtils.isBlank(dto.getName())) {
            throw new RuntimeException("课程名称不能为空");
        }
        if (StringUtils.isBlank(dto.getPic())) {
            throw new RuntimeException("课程图片不能为空");
        }
        if (StringUtils.isBlank(dto.getSt())) {
            throw new RuntimeException("小分类不能为空");
        }
        if (StringUtils.isBlank(dto.getTeachmode())) {
            throw new RuntimeException("教学模式不能为空");
        }
        if (StringUtils.isBlank(dto.getUsers())) {
            throw new RuntimeException("适用人群不能为空");
        }
    }
}
